import Chess from './Chess';
import Rule from './Rule';
import {chessListMap} from './chessData';
import store from '@/vuex';
import {ElMessageBox} from 'element-plus';
import router from '@/router';

//绘制象棋
class DrawChess {
    constructor(opts) {
        this.initData(opts);
        //初始化canvas工具
        this.initCanvas();
        //初始化事件
        this.initEvent();
        //比赛计时
        this.handleTimer();
    }

    //监听事件
    initEvent() {
        this.canvas.addEventListener('click', (e) => {
            if (!this.canClick) {
                return;
            }
            let x = e.pageX - this.canvas.offsetLeft - this.canvas.parentElement.offsetLeft;
            let y = e.pageY - this.canvas.offsetTop - this.canvas.parentElement.offsetTop;
            this.mouseClickPosition = {x: x * this.dpr, y: y * this.dpr};
            console.log(this.mouseClickPosition);
            this.initChessboard();
        })
    }

    //比赛计时
    handleTimer() {
        const {userInfo, matchId, enemy, times} = this;
        this.timer = window.setTimeout(async () => {
            let chessTime = store.getters.getChessTime;
            if (!chessTime) {
                let date = new Date();
                store.dispatch('handleSetChessTime', date);
                chessTime = date;
            }
            const createdAtTime = new Date(chessTime).getTime();
            let currentTime = Date.now();
            let matchTimes = Math.floor((currentTime - createdAtTime) / 1000);
            if (matchTimes > times * 60) {
                window.clearTimeout(this.timer);
                this.timer = null;
                store.dispatch('handleSetChessTime', null);
                let sendData = {
                    chessData: {
                        currentUserId: userInfo.id,
                        list: await this.getNewChessData()
                    },
                    matchId,
                    enemy,
                    isFinish: true
                };
                sendData['winnerId'] = this.canClick ? enemy : userInfo.id;
                if (sendData['winnerId'] === userInfo.id) {
                    ElMessageBox.alert('比赛时间结束，你赢了', '比赛结果', {
                        type: 'success',
                        confirmButtonText: 'OK',
                        async callback() {
                            await router.back();
                        }
                    });
                } else {
                    ElMessageBox.alert('比赛时间结束，你输了', '比赛结果', {
                        type: 'fail',
                        confirmButtonText: 'OK',
                        async callback() {
                            await router.back();
                        }
                    });
                }
                this.proxy.$socket.io.emit('sendChessData', sendData);
            } else {
                this.getMatchTimes(times * 60 - matchTimes);
                this.handleTimer();
            }
        }, 1000)
    }

    //清空计时器
    clearTimer() {
        if (this.timer) {
            window.clearTimeout(this.timer);
            this.timer = null;
            store.dispatch('handleSetChessTime', null);
        }
    }

    //重置计时器
    resetTimer() {
        if (this.timer) {
            window.clearTimeout(this.timer);
            this.timer = null;
            store.dispatch('handleSetChessTime', null);
            this.handleTimer();
            this.getMatchTimes(this.times * 60);
        }
    }

    //初始化数据
    initData(opts) {
        this.radius = 26;//棋子半径
        this.mouseClickPosition = null;//鼠标位置
        this.currentSelectChessIndex = -1;//当前选中的棋子位置
        this.currentCamp = opts.camp || 1;//当前阵营1-黑方、2-红方
        this.timer = null;//计时器
        this.times = 1.5;//比赛时间（分钟）
        this.getMatchTimes = opts.getMatchTimes;
        //默认数据
        let defaultOpts = {
            width: 300,//棋盘宽
            height: 400,//棋盘高
            offsetLeft: 26,//白色区域距离左边界偏移
            offsetTop: 26,//白色区域距离上边界偏移
            innerOffsetLeft: 5,//线框距离白色区域左边界偏移
            innerOffsetTop: 5,//线框距离白色区域上边界偏移
            positionSpacing: 54,//双方阵地中间间隔
            bgColor: '#9b8d80',//棋盘背景色
            innerBgColor: '#ece9ec',//棋盘内框背景色
            lineWidth: 1,//线条宽度
            lineColor: '#000',//线条颜色
        };
        this.opts = Object.assign(defaultOpts, opts);
        this.canvas = opts.canvas;
        this.proxy = opts.proxy;
        this.enemy = opts.enemy;
        this.matchId = opts.matchId;
        this.userInfo = opts.userInfo;
        //创建棋子列表
        this.initChessList(opts);
        //规则类
        this.rule = new Rule({chessList: this.chessList, currentCamp: this.currentCamp});
    }

    //初始化棋子数据
    initChessList(opts) {
        const {chessData, userInfo} = opts;
        if (chessData) {//如果数据库有保存棋子列表
            let currentUserId = chessData.currentUserId;
            //创建棋子列表
            this.chessList = [];
            for (let i = 0; i < chessData.list.length; i++) {
                this.chessList.push(new Chess({radius: this.radius, ...chessData.list[i]}));
            }
            if (parseInt(currentUserId) === parseInt(userInfo.id)) {
                this.canClick = false;
            } else {
                this.canClick = true;
                DrawChess.changChessPosition(this.chessList);
            }
        } else {
            store.dispatch('handleSetChessTime', null);
            this.canClick = opts.camp === 2;//是否可点击棋子，红方先走棋
            //创建棋子列表
            this.chessList = [];
            for (let i = 0; i < chessListMap.length; i++) {
                this.chessList.push(new Chess({radius: this.radius, ...chessListMap[i]}));
            }
            if (parseInt(this.currentCamp) === 1) {
                DrawChess.changChessPosition(this.chessList);
            }
        }
    }

    //根据红、黑方调换棋子位置
    static changChessPosition(chessList) {
        for (let i = 0; i < chessList.length; i++) {
            chessList[i]['y'] = 9 - chessList[i]['y'];
            chessList[i]['x'] = 8 - chessList[i]['x'];
        }
    }

    //初始化canvas工具
    initCanvas() {
        this.ctx = this.canvas.getContext('2d');
        const dpr = window.devicePixelRatio;
        this.canvas.width = this.opts.width * dpr;
        this.canvas.height = this.opts.height * dpr;
        this.canvas.style.width = this.canvas.width / dpr + 'px';
        this.canvas.style.height = this.canvas.height / dpr + 'px';
        this.dpr = dpr;
        this.canvasWidth = this.canvas.width;
        this.canvasHeight = this.canvas.height;
        this.initChessboard();
    }

    //初始化棋盘
    initChessboard() {
        const {ctx, opts, canvasWidth, canvasHeight} = this;
        ctx.clearRect(0, 0, canvasWidth, canvasHeight);
        ctx.save();
        //绘制棋盘背景色
        ctx.fillStyle = opts.bgColor;
        ctx.fillRect(0, 0, canvasWidth, canvasHeight);
        //绘制棋盘内框背景色
        ctx.fillStyle = opts.innerBgColor;
        ctx.fillRect(opts.offsetLeft, opts.offsetTop, canvasWidth - opts.offsetLeft * 2, canvasHeight - opts.offsetTop * 2);
        ctx.restore();
        //绘制线条
        this.drawLine();
    }

    //绘制线条
    drawLine() {
        const {ctx, opts, canvasWidth, canvasHeight, dpr} = this;
        let allHeight = canvasHeight - opts.offsetTop * 2 - opts.innerOffsetTop * 2 - opts.positionSpacing;
        let allWidth = canvasWidth - opts.offsetTop * 2 - opts.innerOffsetTop * 2;
        let singleHeight = allHeight / 8;
        let singleWidth = allWidth / 8;
        let coordinateX = [];
        let coordinateY = [];
        for (let i = 0; i <= 8; i++) {
            ctx.beginPath();
            ctx.save();
            ctx.lineWidth = opts.lineWidth * dpr;
            ctx.strokeStyle = opts.lineColor;
            ctx.lineCap = 'round';
            let x = opts.offsetLeft + opts.innerOffsetLeft + i * singleWidth;
            coordinateX.push(x);
            if (i === 0 || i === 8) {
                ctx.moveTo(x, opts.offsetTop + opts.innerOffsetTop);
                ctx.lineTo(x, opts.offsetTop + opts.innerOffsetTop + allHeight + opts.positionSpacing);
            } else {
                ctx.moveTo(x, opts.offsetTop + opts.innerOffsetTop);
                ctx.lineTo(x, opts.offsetTop + opts.innerOffsetTop + 4 * singleHeight);

                ctx.moveTo(x, opts.offsetTop + opts.innerOffsetTop + 4 * singleHeight + opts.positionSpacing);
                ctx.lineTo(x, opts.offsetTop + opts.innerOffsetTop + allHeight + opts.positionSpacing);
            }
            ctx.stroke();
            ctx.restore();
        }
        for (let i = 0; i <= 9; i++) {
            ctx.beginPath();
            ctx.save();
            ctx.lineWidth = opts.lineWidth * dpr;
            ctx.strokeStyle = opts.lineColor;
            ctx.lineCap = 'round';
            let y = 0;
            if (i >= 5) {
                y = opts.offsetTop + opts.innerOffsetTop + opts.positionSpacing + (i - 1) * singleHeight;
                ctx.moveTo(opts.offsetTop + opts.innerOffsetTop, y);
                ctx.lineTo(opts.offsetTop + opts.innerOffsetTop + allWidth, y);
            } else {
                y = opts.offsetTop + opts.innerOffsetTop + i * singleHeight;
                ctx.moveTo(opts.offsetTop + opts.innerOffsetTop, y);
                ctx.lineTo(opts.offsetTop + opts.innerOffsetTop + allWidth, y);
            }
            coordinateY.push(y);
            ctx.stroke();
            ctx.restore();
        }
        this.coordinateX = coordinateX;
        this.coordinateY = coordinateY;
        console.log(coordinateX);
        console.log(coordinateY);
        this.drawCrossLine();
        this.drawPositionLine();
        this.drawText();
    }

    //绘制交叉对角线
    drawCrossLine() {
        const {ctx, coordinateX, coordinateY, opts, dpr} = this;
        let linePosition = [
            {
                moveTo: [3, 0],
                lineTo: [5, 2]
            },
            {
                moveTo: [5, 0],
                lineTo: [3, 2]
            },
            {
                moveTo: [3, 9],
                lineTo: [5, 7]
            },
            {
                moveTo: [5, 9],
                lineTo: [3, 7]
            }
        ];
        ctx.save();
        ctx.lineWidth = opts.lineWidth * dpr;
        ctx.strokeStyle = opts.lineColor;
        ctx.lineCap = 'round';
        for (let i = 0; i < linePosition.length; i++) {
            const position = linePosition[i];
            ctx.save();
            ctx.moveTo(coordinateX[position.moveTo[0]], coordinateY[position.moveTo[1]]);
            ctx.lineTo(coordinateX[position.lineTo[0]], coordinateY[position.lineTo[1]]);
            ctx.stroke();
            ctx.restore();
        }
        ctx.restore();
    }

    //绘制位置线
    drawPositionLine() {
        const {ctx, coordinateX, coordinateY, opts, dpr} = this;
        const linePosition = [
            {
                coordinate: [0, 3],//坐标
                quadrant: [1, 2]//象限
            },
            {
                coordinate: [1, 2],
                quadrant: [1, 2, 3, 4]
            },
            {
                coordinate: [7, 2],
                quadrant: [1, 2, 3, 4]
            },
            {
                coordinate: [2, 3],
                quadrant: [1, 2, 3, 4]
            },
            {
                coordinate: [4, 3],
                quadrant: [1, 2, 3, 4]
            },
            {
                coordinate: [6, 3],
                quadrant: [1, 2, 3, 4]
            },
            {
                coordinate: [8, 3],
                quadrant: [3, 4]
            },
            {
                coordinate: [0, 6],//坐标
                quadrant: [1, 2]//象限
            },
            {
                coordinate: [1, 7],
                quadrant: [1, 2, 3, 4]
            },
            {
                coordinate: [7, 7],
                quadrant: [1, 2, 3, 4]
            },
            {
                coordinate: [2, 6],
                quadrant: [1, 2, 3, 4]
            },
            {
                coordinate: [4, 6],
                quadrant: [1, 2, 3, 4]
            },
            {
                coordinate: [6, 6],
                quadrant: [1, 2, 3, 4]
            },
            {
                coordinate: [8, 6],
                quadrant: [3, 4]
            }
        ];
        ctx.save();
        ctx.lineWidth = opts.lineWidth * dpr;
        ctx.strokeStyle = opts.lineColor;
        ctx.lineCap = 'round';
        for (let i = 0; i < linePosition.length; i++) {
            const position = linePosition[i];
            let x = Math.round(coordinateX[position.coordinate[0]]);
            let y = Math.round(coordinateY[position.coordinate[1]]);
            let quadrant = position.quadrant;
            let offset = 5;
            let lineLen = 10;
            for (let j = 0; j < quadrant.length; j++) {
                switch (quadrant[j]) {
                    case 1:
                        ctx.moveTo(x + offset, y - offset);
                        ctx.lineTo(x + offset, y - offset - lineLen);
                        ctx.stroke();
                        ctx.moveTo(x + offset, y - offset);
                        ctx.lineTo(x + offset + lineLen, y - offset);
                        ctx.stroke();
                        break;
                    case 2:
                        ctx.moveTo(x + offset, y + offset);
                        ctx.lineTo(x + offset, y + offset + lineLen);
                        ctx.stroke();
                        ctx.moveTo(x + offset, y + offset);
                        ctx.lineTo(x + offset + lineLen, y + offset);
                        ctx.stroke();
                        break;
                    case 3:
                        ctx.moveTo(x - offset, y + offset);
                        ctx.lineTo(x - offset, y + offset + lineLen);
                        ctx.stroke();
                        ctx.moveTo(x - offset, y + offset);
                        ctx.lineTo(x - offset - lineLen, y + offset);
                        ctx.stroke();
                        break;
                    case 4:
                        ctx.moveTo(x - offset, y - offset);
                        ctx.lineTo(x - offset, y - offset - lineLen);
                        ctx.stroke();
                        ctx.moveTo(x - offset, y - offset);
                        ctx.lineTo(x - offset - lineLen, y - offset);
                        ctx.stroke();
                        break;
                }
            }
        }
    }

    //绘制文字
    drawText() {
        const {ctx, opts, canvasWidth, canvasHeight} = this;
        let x1 = canvasWidth / 4;
        let x2 = canvasWidth / 4 * 3;
        let y = canvasHeight / 2;
        ctx.save();
        ctx.fillStyle = opts.lineColor;
        ctx.font = "24px bold serif";
        ctx.textAlign = 'center';
        ctx.textBaseline = 'middle';
        ctx.save();
        ctx.translate(x1, y);
        ctx.rotate(-Math.PI / 2);
        ctx.fillText('楚', 0, -15);
        ctx.fillText('河', 0, 15);
        ctx.restore();
        ctx.save();
        ctx.translate(x2, y);
        ctx.rotate(Math.PI / 2);
        ctx.fillText('漢', 0, -15);
        ctx.fillText('界', 0, 15);
        ctx.restore();
        ctx.restore();
        this.drawBlankChess();
        this.drawChess();
    }

    //绘制棋子
    drawChess() {
        let {ctx, coordinateX, coordinateY, chessList} = this;
        for (let i = 0; i < chessList.length; i++) {
            if (chessList[i].active) {
                chessList[i].draw(ctx, coordinateX, coordinateY);
            }
        }
    }

    //绘制空白棋子（为了获取点击事件）
    drawBlankChess() {
        let {ctx, coordinateX, coordinateY, radius, mouseClickPosition} = this;
        for (let x = 0; x <= 8; x++) {
            for (let y = 0; y <= 9; y++) {
                let positionX = coordinateX[x];
                let positionY = coordinateY[y];
                ctx.save();
                ctx.beginPath();
                ctx.globalAlpha = 0;
                ctx.fillStyle = '#fff';
                ctx.arc(positionX, positionY, radius, 0, Math.PI * 2);
                ctx.fill();
                if (mouseClickPosition) {
                    if (ctx.isPointInPath(mouseClickPosition.x, mouseClickPosition.y)) {
                        this.mouseClickPosition = null;//清空位置信息
                        this.selectCallback({x, y});
                    }
                }
                ctx.restore();
            }
        }
    }

    //点击空白棋子回调函数
    selectCallback(data) {
        const {currentSelectChessIndex, chessList, currentCamp, rule} = this;
        let {selectIndex, selectChess} = this.getSelectChess(data);
        if (currentSelectChessIndex > -1) {//第二次点击
            if (selectIndex === currentSelectChessIndex) {
                chessList[selectIndex]['select'] = false;
                this.currentSelectChessIndex = -1;
            } else {
                const {userInfo, matchId, enemy} = this;
                console.log(matchId);
                rule.check(currentSelectChessIndex, selectIndex, data, async (data) => {
                    this.chessNewPosition = data;
                    let sendData = {
                        chessData: {
                            currentUserId: userInfo.id,
                            list: await this.getNewChessData()
                        },
                        matchId,
                        enemy,
                        isFinish: data.isFinish
                    };
                    let winnerId = 0;
                    if (data.isFinish) {
                        winnerId = currentCamp === data.winner ? userInfo.id : enemy;
                    }
                    sendData['winnerId'] = winnerId;
                    console.log(sendData);
                    this.proxy.$socket.io.emit('sendChessData', sendData);
                });
            }
        } else {//第一次点击
            if (selectIndex > -1 && selectChess.camp === currentCamp) {
                this.currentSelectChessIndex = selectIndex;
                chessList[selectIndex]['select'] = true;
            }
        }
    }

    //获取选中的棋子
    getSelectChess(data) {
        const chessList = this.chessList;
        let selectIndex = -1;
        let selectChess = null;
        for (let i = 0; i < chessList.length; i++) {
            let item = chessList[i];
            if (item.active && item.x === data.x && item.y === data.y) {
                selectIndex = i;
                selectChess = item;
                break;
            }
        }
        return {selectIndex, selectChess};
    }

    //获取最新棋子列表数据
    async getNewChessData() {
        const {chessList} = this;
        let list = [];
        for (let i = 0; i < chessList.length; i++) {
            let chess = chessList[i];
            let chessData = chess.getChessData();
            list.push(chessData);
        }
        return list;
    }

    //棋子回退
    resetChessData() {
        const {chessList, chessNewPosition: {selectIndex, currentSelectChessIndex, xDistance, yDistance}} = this;
        if (selectIndex > -1) {
            chessList[selectIndex].active = true;
        }
        chessList[currentSelectChessIndex].x = chessList[currentSelectChessIndex].x - xDistance;
        chessList[currentSelectChessIndex].y = chessList[currentSelectChessIndex].y - yDistance;
        this.rule = new Rule({chessList: chessList, currentCamp: this.currentCamp});
        this.initChessboard();
    }

    //更新棋子
    updateChessData(update) {
        if (!update) {
            this.resetChessData();
        } else {
            this.canClick = false;
        }
    }

    //根据对方发过来的棋子数据更新
    updateEnemyChess(chessListData) {
        console.log(chessListData);
        this.currentSelectChessIndex = -1;
        this.canClick = true;
        this.chessList = [];
        for (let i = 0; i < chessListData.length; i++) {
            this.chessList.push(new Chess({radius: this.radius, ...chessListData[i]}));
        }
        DrawChess.changChessPosition(this.chessList);
        this.rule = new Rule({chessList: this.chessList, currentCamp: this.currentCamp});
        this.initChessboard();
    }
}

export default DrawChess;